package com.prizedraw.prize_draw.controller;


import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.prizedraw.prize_draw.common.dto.PassDto;
import com.prizedraw.prize_draw.common.dto.UserSearchDto;
import com.prizedraw.prize_draw.common.lang.Const;
import com.prizedraw.prize_draw.common.dto.UserMenuDto;
import com.prizedraw.prize_draw.common.lang.Result;
import com.prizedraw.prize_draw.entity.*;
import com.prizedraw.prize_draw.mapper.SysUserMapper;
import com.prizedraw.prize_draw.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;


/**
 * <p>
 *  用户控制层
 * </p>
 *
 * @author czj666
 * @since 2021-09-07
 */
@RestController
@RequestMapping("/sys/user")
public class SysUserController extends BaseController {

    @Autowired
    BCryptPasswordEncoder passwordEncoder;

    @Autowired
    SysUserService sysUserService;

    @Autowired
    SysRoleService sysRoleService;

    @Autowired
    DepartmentRoleService departmentRoleService;

    @Autowired
    UserDepartmentRoleService userDepartmentRoleService;

    @Autowired
    SysUserMenuService sysUserMenuService;

    @Autowired
    SysUserMapper sysUserMapper;

    @GetMapping("/listAll")
    @PreAuthorize("hasAuthority('sys:user:list')")
    public Result listAll(){

        List<SysUser> sysUsers = sysUserService.list(new QueryWrapper<SysUser>()
                .and(wrapper -> wrapper.ne("user_id","666666")));

        return Result.succ(sysUsers);
    }


    @GetMapping("/list")
    @PreAuthorize("hasAuthority('sys:user:list')")
    public Result list(UserSearchDto userSearchDto){
        //boolean condition表示该条件是否加入最后生成的sql中
        Page<SysUser> users = sysUserService.page(getPage(),
                new QueryWrapper<SysUser>().
                        like(StrUtil.isNotBlank(userSearchDto.getUsername()), "user_name", userSearchDto.getUsername())
                        .in(StrUtil.isNotBlank(userSearchDto.getDepartmentName()), "id",sysUserMapper.listUserIdByLikeDeptName(userSearchDto.getDepartmentName()))
                        .and(wrapper -> wrapper.ne("user_id","666666"))
                        );

                        
        users.getRecords().forEach(u -> {
            u.setDepartmentRoles(departmentRoleService.listDepartmentRoleByUserId(u.getId()));

            // 这里为了回显不用再次查询数据库，将回显会用到的数据，也进行查询并返回回去，
            // 这样子关联的查询多了，这个Result对象好像变重了不太好，太重应采取回显再来查询单个比较好
            List<SysUserMenu> sysUserMenus = sysUserMenuService.list(new QueryWrapper<SysUserMenu>().eq("user_id", u.getId()));
            List<Integer> menuIds = sysUserMenus.stream().map(sysUserMenu -> sysUserMenu.getMenuId()).collect(Collectors.toList());
            u.setMenuIds(menuIds);
        });

        return Result.succ(users);
    }

    @PreAuthorize("hasAuthority('sys:user:save')")
    @PostMapping("/save")
    public Result save(@Validated  @RequestBody SysUser sysUser){
        // 随便生成一个不重复的6位数的工号
        String userId = "";
        do {
            userId = RandomUtil.randomNumbers(6);
        }while (sysUserService.count(new QueryWrapper<SysUser>().eq("user_id",userId)) != 0);
        sysUser.setUserId(userId);
        // 设置默认密码
        sysUser.setPassowrd(passwordEncoder.encode(Const.DEFAULT_PASSWORD));
        sysUserService.save(sysUser);
        if (sysUser.getDepartmentRoles() != null){
            // 如果部门岗位不为空，则将其封装返回来的部门id和岗位id去查询关联表中的id是多少，然后与用户id进行保存到user_department_role
            userDepartmentRoleService.save(sysUser.getId(),sysUser.getDepartmentRoles());
        }

        return Result.succ(sysUser);
    }

    @PreAuthorize("hasAuthority('sys:user:update')")
    @PostMapping("/update")
    @Transactional
    public Result update(@Validated  @RequestBody SysUser sysUser){

        sysUserService.updateById(sysUser);

        // 更新则为了节省麻烦，怎么可能去查他要保存的部门岗位有没有，没有才添加，有它没有的则删除-- 干脆一点，直接删了，重新保存
        userDepartmentRoleService.remove(new QueryWrapper<UserDepartmentRole>().eq("user_id", sysUser.getId()));
        if (sysUser.getDepartmentRoles() != null){
            userDepartmentRoleService.save(sysUser.getId(),sysUser.getDepartmentRoles());
        }

        return Result.succ(sysUser);
    }

    @PreAuthorize("hasAuthority('sys:user:delete')")
    @Transactional
    @PostMapping("/delete")
    public Result delete(@RequestBody Integer[] ids){

        sysUserService.removeByIds(Arrays.asList(ids));
        userDepartmentRoleService.remove(new QueryWrapper<UserDepartmentRole>().in("user_id", ids));

        return Result.succ("");
    }


    @PostMapping("/updatePass")
    public Result updatePass(@Validated @RequestBody PassDto passDto, Principal principal){
        SysUser sysUser = sysUserService.getByUserId(principal.getName());

        boolean matches = passwordEncoder.matches(passDto.getCurrentPass(), sysUser.getPassowrd());
        if (!matches){
            return Result.fail("旧密码不正确");
        }

        sysUser.setPassowrd(passwordEncoder.encode(passDto.getPassword()));
        sysUserService.updateById(sysUser);

        return Result.succ("");
    }

    @PreAuthorize("hasAuthority('sys:user:repass')")
    @PostMapping("/repass")
    public Result repass(@RequestBody String userId){
        SysUser sysUser = sysUserService.getById(userId);
        sysUser.setPassowrd(passwordEncoder.encode(Const.DEFAULT_PASSWORD));
        sysUserService.updateById(sysUser);
        return Result.succ("");
    }

    @Transactional
    @PreAuthorize("hasAuthority('sys:perm:list')")
    @PostMapping("/perm/{userId}")
    public Result perm(@PathVariable Integer userId, @RequestBody Integer[] menuIds){
        //新建一个list集合，等会用户批量插入
        List<SysUserMenu> sysUserMenus = new ArrayList<>();
        //将所有用户和菜单权限id实例化成对象，等会用于关联表的插入
        Arrays.stream(menuIds).forEach(menuId -> {
            SysUserMenu sysUserMenu = new SysUserMenu();
            sysUserMenu.setUserId(userId);
            sysUserMenu.setMenuId(menuId);
            sysUserMenus.add(sysUserMenu);
        });
        //直接删除所有的
        sysUserMenuService.remove(new QueryWrapper<SysUserMenu>().eq("user_id",userId));
        //进行重新保存
        sysUserMenuService.saveBatch(sysUserMenus);
        //改变了权限，清除在redis为了防止频繁查询用户的权限的缓存
        sysUserService.clearUserAuthorityInfo(userId);
        return Result.succ(menuIds);
    }

    @Transactional
    @PreAuthorize("hasAuthority('sys:perm:list')")
    @PostMapping("/permBatch")
    public Result permBatch(@RequestBody UserMenuDto userMenuDto){
        //下面是czj666
        // 依葫芦画瓢，将用户的授权用一个用户数组id循环起来形成一个批量，只能想到这样，上面用到dto,因为记得在body里面的数据，只能传给一个
        // 对这个用户直接授权产生疑问？是否真的是这样做？直接把权限赋予用户，而不用角色作为一个权限的集合来进行权限的管理，
        // 如果用户过多，权限有很多项，那这个关联表岂不是n条，各自各的权限，
        // 除非权限是很大的一项（或是一个有点关键的操作？），一个大的概括，如：用户管理，就能有权限进行操作有关用户的功能
        // 而且角色明显，能操作的一般后台的就那几个角色，如果将角色作为权限的集合，岂不是直接赋予角色就能操作该需要操作的权限(可能因为抽奖这里觉得有对应操作就一定那个角色)，更直接简单，易懂的操作，--还没有查到什么权限设计思想...
        // 而不会导致对其权限赋予用户很陌生(灵活倒是有一点点灵活)，一般知道角色就知道能操作什么。。。，对于抽奖分角色就知道功能
        //新建一个list集合，等会用户批量插入
        List<SysUserMenu> sysUserMenus = new ArrayList<>();
        //将所有用户和菜单权限id实例化成对象，等会用于关联表的插入
        Arrays.stream(userMenuDto.getUserIds()).forEach(userId -> {
            Arrays.stream(userMenuDto.getMenuIds()).forEach(menuId -> {
                SysUserMenu sysUserMenu = new SysUserMenu();
                sysUserMenu.setUserId(userId);
                sysUserMenu.setMenuId(menuId);
                sysUserMenus.add(sysUserMenu);
            });
            //直接删除所有的
            sysUserMenuService.remove(new QueryWrapper<SysUserMenu>().eq("user_id",userId));
            //改变了权限，清除在redis为了防止频繁查询用户的权限的缓存
            sysUserService.clearUserAuthorityInfo(userId);
        });
        //进行重新保存
        sysUserMenuService.saveBatch(sysUserMenus);
        return Result.succ("");
    }

    @PostMapping(value = "/import")
    public Result excelImport(@RequestParam("excel") MultipartFile excel) throws IOException {
        return sysUserService.excelImport(excel);
    }

    /*@PostMapping(value = "/import")
    //headLineNum 表头所在行数，默认为第一行
    public Object readExcel(@RequestParam("excel") MultipartFile excel) throws IOException {
        List<Object> userExcel = null;
        try {
            userExcel = sysUserService.importUserExcel(excel, new UserDB(), 1);
            if (userExcel == null) {
                log.error("请传入正确的excel格式!");
                return Result.fail("请传入正确的excel格式");
            }
        } catch (ExcelNullPointException e) {
            e.printStackTrace();
            log.error("表格数据存在空值");
            return Result.fail("表格数据存在空值");
        } catch (ExcelException e) {
            e.printStackTrace();
            log.error("表中含有不存在的部门");
            return Result.fail("表中含有不存在的部门");
        } catch (Exception e) {
            e.printStackTrace();
            log.error("无法导入数据库,请查看配置参数是否正确!");
            return Result.fail("无法导入数据库,请查看配置参数是否正确!");
        }
        log.info("恭喜,导入excel成功!");
        return Result.succ("");
    }*/


}
